<?php 

class ImportXML {
	
	private static $instance = null;
	private $shopId = null;
	private $db = null;
	private $defaultLanguageId = null;
	private $languagesArray = array();
	private $categoriesArray = array();
	private $now = null;
	
	public function __construct($shopId) {
		if(empty ($shopId))
		{
			throw new Exception("Cant create ImportXML object", 0, null);
		}
		$this->shopId = $shopId;
		$this->defaultLanguageId = Config::Get('default_language_id');
		$this->defaultLanguageId = $this->defaultLanguageId[0];
		$this->db = Registry::Get('db');
		$this->loadLanguages();
		$this->loadCategories();
		$this->now = date("Y-m-d H:i", time());
	}
	
	/**
	 *
	 * @param int $shopId
	 * @return ImportXML 
	 */
	public static function instance($shopId = null)
	{
		if(self::$instance === null)
		{
			self::$instance = new ImportXML($shopId);
		}
		return self::$instance;
	}
	
	public function parseXml($xmlString)
	{
		if(!empty($xmlString))
		{
			$xmlObject = new SimpleXMLElement($xmlString);
			$products = $xmlObject->xpath('/root/products/product');
			if(!empty($products))
			{
				$allProductsCodesArray = array();
				while(list( , $product) = each($products))
				{
					if(!isset($product->code))
					{
						continue;
					}
					$arrayKey = trim((string)$product->code);
					if(empty($arrayKey))
					{	
						continue;
					} 
					$allProductsCodesArray[$arrayKey] = $product;
				}
				$this->db->BeginTransaction();
				$this->parseProductsArray($allProductsCodesArray);
				$this->db->CommitTransaction();
			}
		}
	}
	
	/** that's all, everything below this line is unimportant ;) **/
	
	private function query($sql, $show = false)
	{
		if($show)
		{
			var_dump($sql);
		}
		return $this->db->prepare($sql)->execute()->FetchAllAssoc();
	}
	
	private function loadLanguages()
	{
		$sql = 'SELECT * FROM language WHERE active = 1';
		$languages = $this->query($sql);
		foreach($languages as $languageRow)
		{
			$this->languagesArray['k-' . $languageRow['code']] = $languageRow['id_language']; 
			$this->languagesArray['k-' . $languageRow['id_language']] = $languageRow['code'];
		}
	}
	
	private function loadCategories()
	{
		// kategorie
		$sql = sprintf('SELECT * FROM category LEFT JOIN category_description ON (category.id_category = category_description.id_category) WHERE category_description.id_language = %d', $this->defaultLanguageId);	
		$categories = $this->query($sql);
		if(empty ($categories))
		{
			return;
		}
		$tempCategoriesArray = array(
			'parent' => array(),
			'children' => array()
		);
		foreach($categories as $category)
		{
			if($category['parent'] == 0)
			{
				$tempCategoriesArray['parent'][$category['name']] = $category['id_category'];
			} else {
				$tempCategoriesArray['children'][$category['parent']][$category['name']] = $category['id_category'];
			}
		}
		
		foreach($tempCategoriesArray['parent'] as $k => $v)
		{
			if(isset($tempCategoriesArray['children'][$v]))
			{
				$tempCategoriesArray['parent'][$k] = $tempCategoriesArray['children'][$v];
				unset($tempCategoriesArray['children'][$v]);
			}
		}
		$this->categoriesArray = $tempCategoriesArray['parent'];
	}
	
	private function inserDescription($productToInsert, $id)
	{
		$descArr = array();
		foreach($productToInsert->languages->language as $language)
		{
			if(!isset($this->languagesArray['k-' . (string)$language['code']]))
			{
				continue;
			}
			
			$descArr[] = sprintf(
					'(\'%s\', \'%s\', \'%s\', \'%s\')', 
					$id,
					$this->languagesArray['k-' . (string)$language['code']],
					(string)$language->name,
					(string)$language->description
					);
		}
		if(!empty($descArr))
		{
			$sql = 'INSERT INTO product_shop_description (id_product_shop, id_language, name, description) VALUES ' . implode(', ', $descArr);
			$this->query($sql);
		}		
	}		
			
	
	private function insertProduct($productToInsert, $productKey)
	{
		$productShop = new ProductShop();
		$productShop->setIdShop($this->shopId);
		$productShop->setIdProduct($productKey);
		$productShop->setPrice($productToInsert->price);
		$productShop->setShipping($productToInsert->shipping);
		$productShop->setDate($this->now);
		$productShop->setUrl($productToInsert->url);
		$productShop->setCurrency($productToInsert->currency);
		$productShop->setActive($productToInsert->avialable);
		$id = ProductShopDAL::Insert($productShop->GetDalDataObj());
		$this->inserDescription($productToInsert, $id);
	}
	
	private function updateAssignedProducts($allProductsCodesArray)
	{
		$existingProducts = $this->query('SELECT * FROM product WHERE code = \'' . implode(array_keys($allProductsCodesArray), '\' OR code = \'') . '\'');
		
		if(empty($existingProducts))
		{
			return $allProductsCodesArray;
		}
		
		$existingProductsCodeArray = array();
		foreach($existingProducts as $eProduct)
		{
			$existingProductsCodeArray[$eProduct['id_product']] = $allProductsCodesArray[trim($eProduct['code'])];
			unset($allProductsCodesArray[trim($eProduct['code'])]);
		}

		// update produktow ktore sa przypisane do sklepu
		$productsToUpdate = $this->query(sprintf('SELECT * FROM product_shop WHERE id_shop = %d AND (id_product = %s)', $this->shopId, implode(array_keys($existingProductsCodeArray), ' OR id_product = ')));

		if(!empty($productsToUpdate))
		{	
			$productsIds = array();

			foreach($productsToUpdate as $productToUpdateLine)
			{
				$actualProduct = $existingProductsCodeArray[$productToUpdateLine['id_product']];
				unset($existingProductsCodeArray[$productToUpdateLine['id_product']]);
				$sql = sprintf('UPDATE product_shop SET price = \'%s\', shipping = \'%s\', date = \'%s\', url = \'%s\', currency = \'%s\', active = \'%s\' WHERE id_product_shop = %d', (float)$actualProduct->price, (float)$actualProduct->shipping, $this->now, (string)$actualProduct->url, (string)$actualProduct->currency, (bool)$actualProduct->avialable, (int)$productToUpdateLine['id_product_shop']);
				$this->query($sql);

				$sql = sprintf('DELETE FROM product_shop_description WHERE id_product_shop = %d', $productToUpdateLine['id_product_shop']);
				$this->query($sql);

				$this->inserDescription($actualProduct, $productToUpdateLine['id_product_shop']);
			}
		}
		
		if(!empty($existingProductsCodeArray))
		{
			foreach($existingProductsCodeArray as $productKey => $productToInsert)
			{
				$this->insertProduct($productToInsert, $productKey);
												
			}
		}		
		return $allProductsCodesArray;
	}
	
	private function updateProductsBySearch($allProductsCodesArray)
	{
		/**
		 * @todo: try to find what's wrong
		 */		
		return;
		if(!empty($productsCodesArray))
		{
			foreach($productsCodesArray as $product)
			{
				$nameData = array();
				foreach($product->languages->language as $language)
				{
					$nameData[] = '(' . 'id_language = ' . $this->languagesArray['k-' . $language['code']] . 'AND name LIKE \'' . trim($language->name) . '\')';
				}
				if(!empty($nameData))
				{
					$res = $this->query('SELECT id_product FROM product_description WHERE ' . implode(' OR ', $nameData));
					if(count($res == 1))
					{
						// mozna przypisac
					}
				}
			}
		}		
	}
	
	private function insertNewProducts($allProductsCodesArray)
	{
		$sql = 'SELECT * FROM manufacturer';
		$manufacturers = $this->query($sql);
		if(empty ($manufacturers))
		{
			exit;
		}
		$manufacturersArray = array();
		foreach($manufacturers as $manufacturer)
		{
			$manufacturersArray[$manufacturer['name']] = $manufacturer['id_manufacturer'];
		}						

		foreach($allProductsCodesArray as $product)
		{
			$category = (string)$product->category;
			$subcategory = (string)$product->subcategory;
			$manufacturer = (string)$product->manufacturer;
			echo 'nowy0';
			
			if(
				empty($category) || 
				empty ($subcategory) || 
				empty ($manufacturer) ||
				!isset($this->categoriesArray[$category]) ||
				!isset($this->categoriesArray[$category][$subcategory])	||
				!isset($manufacturersArray[$manufacturer])
			)
			{
				continue;
			}
			$name = null;
			do {
				foreach($product->languages->language as $language)
				{
					if($this->languagesArray['k-' . $language['code']]  == $this->defaultLanguageId)
					{
						$name = $language->name;
					}
				}
			}while($name == null);
			if(empty($name))
			{
				continue;
			}
			$productObj = new Product();
			$productObj->setActive(0);
			$productObj->setCode($product->code);
			$productObj->setSlug(ProductDAL::GenerateUniqueSlug($name));
			$productObj->setIdManufacturer($manufacturersArray[$manufacturer]);
			$productObj->setIdCategory($this->categoriesArray[$category][$subcategory]);
			$productObj->setRank(0);
			$id_product = ProductDAL::Insert($productObj->getDalDataobj());

			foreach($product->languages->language as $language)
			{
				$productDescription = new ProductDescription();
				$productDescription->setIdProduct($id_product);
				$productDescription->setIdLanguage($this->languagesArray['k-' . $language['code']]);
				$productDescription->setDescription($language->description);
				$productDescription->setTechnologies(false);
				$productDescription->setName($language->name);
				$productDescription->setSeoKeywords(false);
				$productDescription->setSeoDescription(false);
				ProductDescriptionDAL::Insert($productDescription->getDalDataObj());								
			}	

			$this->insertProduct($product, $id_product);
		}		
	}	
	
	private function parseProductsArray($allProductsCodesArray)
	{
		if(empty ($allProductsCodesArray))
		{
			return;
		}
		
		$allProductsCodesArray = $this->updateAssignedProducts($allProductsCodesArray);
		
		if(!empty($allProductsCodesArray))
		{
			$allProductsCodesArray = $this->updateProductsBySearch($allProductsCodesArray);
		}
		
		if(!empty($allProductsCodesArray))
		{
			$allProductsCodesArray = $this->insertNewProducts($allProductsCodesArray);
		}		
	}

}

